use std::{collections::HashMap, net::SocketAddr};

use mio::{
    Events, Interest, Poll, Registry, Token,
    net::{TcpListener, TcpStream},
};

use crate::server::client::ClientState;

use super::client::Client;

pub struct Server {
    server: Option<TcpListener>,
    clients: HashMap<Token, Client>,
    client_id: usize,
}

impl Server {
    pub fn new() -> Self {
        Self {
            server: None,
            clients: HashMap::new(),
            client_id: 0,
        }
    }

    fn handle_connect_event(&mut self, registry: &Registry) {
        let srv = self.server.as_ref().unwrap();

        let socket: TcpStream = match srv.accept() {
            Err(e) => {
                log::warn!("accept error: {}", e);
                return;
            }
            Ok((sock, _)) => sock,
        };
        let mut client = Client::new(socket);
        client.read();

        self.client_id += 1;
        let t = Token(self.client_id);
        self.clients.insert(t, client);

        let client = self.clients.get_mut(&t).unwrap();

        if let Err(e) = registry.register(&mut client.socket, t, Interest::WRITABLE) {
            log::warn!("register error: {}", e);
            return;
        }
        log::info!("listen new client,{:?}", client.get_addr());
    }

    pub fn run(&mut self, addr: &str) -> Result<(), String> {
        let addr = addr.parse::<SocketAddr>().expect("invalid address");
        let mut srv = TcpListener::bind(addr).map_err(|e| e.to_string())?;

        let mut poll = Poll::new().unwrap();
        let token = Token(0);

        poll.registry()
            .register(&mut srv, token, Interest::READABLE)
            .map_err(|e| e.to_string())?;

        self.server = Some(srv);
        let mut events = Events::with_capacity(100);
        loop {
            if let Err(e) = poll.poll(&mut events, None) {
                log::warn!("poll error: {}", e);
                continue;
            }
            let registry = poll.registry();

            for event in &events {
                let _token = event.token();
                if token == _token {
                    self.handle_connect_event(registry);
                    continue;
                }
                let client = match self.clients.get_mut(&_token) {
                    Some(v) => v,
                    None => continue,
                };
                if client.state == ClientState::Closed {
                    if let Err(e) = registry.deregister(&mut client.socket) {
                        log::warn!("deregister error: {}", e);
                    }
                    if let Some(c) = self.clients.remove(&_token) {
                        log::info!("client closed,{}", c.get_addr());
                    }
                    continue;
                }
                if event.is_readable() {
                    client.read();
                    let _ = registry.reregister(&mut client.socket, _token, Interest::WRITABLE);
                }
                if event.is_writable() {
                    client.write();
                    let _ = registry.reregister(&mut client.socket, _token, Interest::READABLE);
                }
            }
        }
    }
}
